Python クライアントライブラリで Google Cloud Storage の参照・作成・更新・削除操作をするにはどのメソッドを使えばよいのか確認してみた
こんにちは、みかみです。
バッチ処理で BigQuery を使う場合に、データのロードやエクスポートなどで GCS を使うケースはよくあります。
やりたいこと
- GCS Python クライアントライブラリから GCS を操作したい
- GCS Python クライアントライブラリのどのメソッドでどんな操作ができるのか確認したい
目次
前提
gcloud CLI や GCS クライアントライブラリを実行できる環境は準備済みです。
- Cloud Storage Client Libraries | Cloud Storage ドキュメント
- Setting up a Python development environment | Python ガイド
- gcloud コマンドライン ツールの概要 | Cloud SDK: コマンドライン インターフェース ドキュメント
サービスアカウントを作成
クライアントライブラリからはサービスアカウントで GCS にアクセスするため、まずは GCS アクセス権限のあるサービスアカウントを gcloud CLI で作成します。
[ec2-user@ip-10-0-43-239 test_gcs]$ gcloud iam service-accounts create test-gcs Created service account [test-gcs].
なお、サービスアカウント名は、英数小文字とハイフンが許容されており、6~30 文字で入力する必要があるとのことです。
アカウント名にアンダースコアを入れようとしたところ、以下のエラーになりました。。
[ec2-user@ip-10-0-43-239 test_gcs]$ gcloud iam service-accounts create test_gcs ERROR: (gcloud.iam.service-accounts.create) argument NAME: Bad value [test_gcs]: Service account name must be between 6 and 30 characters (inclusive), must begin with a lowercase letter, and consist of lowercase alphanumeric characters that can be separated by hyphens. Usage: gcloud iam service-accounts create NAME [optional flags] optional flags may be --description | --display-name | --help For detailed information on this command and its flags, run: gcloud iam service-accounts create --help
続いて、作成したサービスアカウントに GCS を操作するためのロールを付与し、アカウントキーファイルを取得します。
今回はバケット作成などの一連の操作を確認したいため、Storage 管理者の事前定義ロールをサービスアカウントに付与しました。
[ec2-user@ip-10-0-43-239 test_gcs]$ gcloud projects add-iam-policy-binding cm-da-mikami-yuki-258308 --member "serviceAccount:test-gcs@cm-da-mikami-yuki-258308.iam.gserviceaccount.com" --role "roles/storage.admin" Updated IAM policy for project [cm-da-mikami-yuki-258308]. bindings: (省略) - members: - serviceAccount:test-gcs@cm-da-mikami-yuki-258308.iam.gserviceaccount.com role: roles/storage.admin (省略) version: 1 [ec2-user@ip-10-0-43-239 test_gcs]$ gcloud iam service-accounts keys create test-gcs.json --iam-account test-gcs@cm-da-mikami-yuki-258308.iam.gserviceaccount.com created key [034643e95f70ab698a041187e282329b081ee7e6] of type as [test-gcs.json] for [test-gcs@cm-da-mikami-yuki-258308.iam.gserviceaccount.com] [ec2-user@ip-10-0-43-239 test_gcs]$ ls | grep test-gcs.json test-gcs.json
カレントディレクトリにアカウントキーファイルが作成されたことが確認できました。
なお、クライアントライブラリを使用する場合、アカウントキーファイルを環境変数( GOOGLE_APPLICATION_CREDENTIALS )に設定しておくとデフォルトのサービスアカウントとして使用できるので便利ですが、今回は Python コードで使用するサービスアカウントを指定するため、環境変数の設定は省略します。
バケット関連操作
クライアントライブラリから、バケットの参照や作成、更新、削除を実行してみます。
バケット情報参照
google.cloud.storage.Client クラスの list_buckets および get_bucket メソッドで、バケット情報が取得できます。
from google.cloud import storage from google.oauth2 import service_account import os import json from pprint import pprint key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) # get list buckets = client.list_buckets() for obj in buckets: print('-------->') pprint(vars(obj)) # get bucket = client.get_bucket(obj.id) print('\t-------->') pprint(vars(bucket))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python bucket.py --------> {'_acl': <google.cloud.storage.acl.BucketACL object at 0x7faa3d7ca090>, '_changes': set(), '_client': <google.cloud.storage.client.Client object at 0x7faa3d7ba0d0>, '_default_object_acl': <google.cloud.storage.acl.DefaultObjectACL object at 0x7faa3d7cfdd0>, '_label_removals': set(), '_properties': {'defaultEventBasedHold': False, 'etag': 'CAE=', 'iamConfiguration': {'bucketPolicyOnly': {'enabled': False}, 'uniformBucketLevelAccess': {'enabled': False}}, 'id': 'test-cm-mikami', 'kind': 'storage#bucket', 'location': 'ASIA', 'locationType': 'multi-region', 'metageneration': '1', 'name': 'test-cm-mikami', 'projectNumber': '797147019523', 'selfLink': 'https://www.googleapis.com/storage/v1/b/test-cm-mikami', 'storageClass': 'STANDARD', 'timeCreated': '2020-03-13T04:53:58.641Z', 'updated': '2020-03-13T04:53:58.641Z'}, '_user_project': None, 'name': 'test-cm-mikami'} --------> {'_acl': <google.cloud.storage.acl.BucketACL object at 0x7faa3d7cfcd0>, '_changes': set(), '_client': <google.cloud.storage.client.Client object at 0x7faa3d7ba0d0>, '_default_object_acl': <google.cloud.storage.acl.DefaultObjectACL object at 0x7faa3d7cfb90>, '_label_removals': set(), '_properties': {'defaultEventBasedHold': False, 'etag': 'CAE=', 'iamConfiguration': {'bucketPolicyOnly': {'enabled': False}, 'uniformBucketLevelAccess': {'enabled': False}}, 'id': 'test-cm-mikami', 'kind': 'storage#bucket', 'location': 'ASIA', 'locationType': 'multi-region', 'metageneration': '1', 'name': 'test-cm-mikami', 'projectNumber': '797147019523', 'selfLink': 'https://www.googleapis.com/storage/v1/b/test-cm-mikami', 'storageClass': 'STANDARD', 'timeCreated': '2020-03-13T04:53:58.641Z', 'updated': '2020-03-13T04:53:58.641Z'}, '_user_project': None, 'name': 'test-cm-mikami'} --------> {'_acl': <google.cloud.storage.acl.BucketACL object at 0x7faa3d7cffd0>, '_changes': set(), '_client': <google.cloud.storage.client.Client object at 0x7faa3d7ba0d0>, '_default_object_acl': <google.cloud.storage.acl.DefaultObjectACL object at 0x7faa3d7cfc90>, '_label_removals': set(), '_properties': {'defaultEventBasedHold': False, 'etag': 'CAQ=', 'iamConfiguration': {'bucketPolicyOnly': {'enabled': False}, 'uniformBucketLevelAccess': {'enabled': False}}, 'id': 'test-mikami', 'kind': 'storage#bucket', 'location': 'ASIA-NORTHEAST1', 'locationType': 'region', 'metageneration': '4', 'name': 'test-mikami', 'projectNumber': '797147019523', 'selfLink': 'https://www.googleapis.com/storage/v1/b/test-mikami', 'storageClass': 'STANDARD', 'timeCreated': '2020-03-24T08:47:02.958Z', 'updated': '2020-05-11T09:49:01.521Z'}, '_user_project': None, 'name': 'test-mikami'} --------> {'_acl': <google.cloud.storage.acl.BucketACL object at 0x7faa3d7e6ed0>, '_changes': set(), '_client': <google.cloud.storage.client.Client object at 0x7faa3d7ba0d0>, '_default_object_acl': <google.cloud.storage.acl.DefaultObjectACL object at 0x7faa3d7e6e10>, '_label_removals': set(), '_properties': {'defaultEventBasedHold': False, 'etag': 'CAQ=', 'iamConfiguration': {'bucketPolicyOnly': {'enabled': False}, 'uniformBucketLevelAccess': {'enabled': False}}, 'id': 'test-mikami', 'kind': 'storage#bucket', 'location': 'ASIA-NORTHEAST1', 'locationType': 'region', 'metageneration': '4', 'name': 'test-mikami', 'projectNumber': '797147019523', 'selfLink': 'https://www.googleapis.com/storage/v1/b/test-mikami', 'storageClass': 'STANDARD', 'timeCreated': '2020-03-24T08:47:02.958Z', 'updated': '2020-05-11T09:49:01.521Z'}, '_user_project': None, 'name': 'test-mikami'}
google.cloud.storage.Client クラスには lookup_bucket というメソッドもあり、get_bucket と同じ情報が取得できます。
from google.cloud import storage from google.oauth2 import service_account import os import json from pprint import pprint key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) # get list buckets = client.list_buckets() for obj in buckets: print('-------->') print(obj.id) # lookup bucket = client.lookup_bucket(obj.id) print('\t-------->') pprint(vars(bucket))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python bucket_lookup.py --------> test-cm-mikami --------> {'_acl': <google.cloud.storage.acl.BucketACL object at 0x7f2748a10c50>, '_changes': set(), '_client': <google.cloud.storage.client.Client object at 0x7f27489fc490>, '_default_object_acl': <google.cloud.storage.acl.DefaultObjectACL object at 0x7f2748a10dd0>, '_label_removals': set(), '_properties': {'defaultEventBasedHold': False, 'etag': 'CAE=', 'iamConfiguration': {'bucketPolicyOnly': {'enabled': False}, 'uniformBucketLevelAccess': {'enabled': False}}, 'id': 'test-cm-mikami', 'kind': 'storage#bucket', 'location': 'ASIA', 'locationType': 'multi-region', 'metageneration': '1', 'name': 'test-cm-mikami', 'projectNumber': '797147019523', 'selfLink': 'https://www.googleapis.com/storage/v1/b/test-cm-mikami', 'storageClass': 'STANDARD', 'timeCreated': '2020-03-13T04:53:58.641Z', 'updated': '2020-03-13T04:53:58.641Z'}, '_user_project': None, 'name': 'test-cm-mikami'} --------> test-mikami --------> {'_acl': <google.cloud.storage.acl.BucketACL object at 0x7f2748a26990>, '_changes': set(), '_client': <google.cloud.storage.client.Client object at 0x7f27489fc490>, '_default_object_acl': <google.cloud.storage.acl.DefaultObjectACL object at 0x7f2748a26b50>, '_label_removals': set(), '_properties': {'defaultEventBasedHold': False, 'etag': 'CAQ=', 'iamConfiguration': {'bucketPolicyOnly': {'enabled': False}, 'uniformBucketLevelAccess': {'enabled': False}}, 'id': 'test-mikami', 'kind': 'storage#bucket', 'location': 'ASIA-NORTHEAST1', 'locationType': 'region', 'metageneration': '4', 'name': 'test-mikami', 'projectNumber': '797147019523', 'selfLink': 'https://www.googleapis.com/storage/v1/b/test-mikami', 'storageClass': 'STANDARD', 'timeCreated': '2020-03-24T08:47:02.958Z', 'updated': '2020-05-11T09:49:01.521Z'}, '_user_project': None, 'name': 'test-mikami'}
クライアントライブラリのコードを確認したところ、内部的には get_bucket を実行していました。
def lookup_bucket(self, bucket_name, timeout=_DEFAULT_TIMEOUT): (省略) try: return self.get_bucket(bucket_name, timeout=timeout) except NotFound: return None
バケット作成
google.cloud.storage.Client クラスの create_bucket で、新規バケットを作成できます。
from google.cloud import storage from google.oauth2 import service_account import os import json key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) bucket_name = 'bucket_mikami' bucket = client.create_bucket(bucket_name) print("Bucket {} created.".format(bucket.name))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python bucket_create.py Bucket bucket_mikami created.
google.cloud.storage.Bucket クラスの create メソッドでも、同じくバケット作成可能です。
(省略) bucket_name = 'bucket_mikami_2' bucket = client.bucket(bucket_name) bucket.create() print("Bucket {} created.".format(bucket.name))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python bucket_create_2.py Bucket bucket_mikami_2 created.
バケット更新
google.cloud.storage.Bucket クラスの update メソッドでは、バケット情報を更新できます。
試しに、ラベルの付与とバージョニング設定を更新してみました。
from google.cloud import storage from google.oauth2 import service_account import os import json key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) bucket_name = 'bucket_mikami' bucket = client.get_bucket(bucket_name) print('labels: {}'.format(bucket.labels)) print('versioning_enabled: {}'.format(bucket.versioning_enabled)) # update bucket.labels = dict(description='test-update') bucket.versioning_enabled = True bucket.update() print("Update bucket {}.".format(bucket.name)) bucket_updated = client.get_bucket(bucket_name) print('labels: {}'.format(bucket_updated.labels)) print('versioning_enabled: {}'.format(bucket_updated.versioning_enabled))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python bucket_update.py labels: {} versioning_enabled: False Update bucket bucket_mikami. labels: {'description': 'test-update'} versioning_enabled: True
なお、ラベルには半角スペースは使用できません。
はじめ、以下のように半角スペース込みの文字列でラベル付与しようとしたところ、Invalid argument エラーになりました。
(省略) # update bucket.labels = dict(description='for test update') bucket.versioning_enabled = True bucket.update() print("Update bucket {}.".format(bucket.name)) (省略)
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python bucket_update.py labels: {} versioning_enabled: False Traceback (most recent call last): File "bucket_update.py", line 23, in <module> bucket.update() File "/home/ec2-user/test_gcs/lib64/python3.7/site-packages/google/cloud/storage/_helpers.py", line 246, in update timeout=timeout, File "/home/ec2-user/test_gcs/lib64/python3.7/site-packages/google/cloud/_http.py", line 423, in api_request raise exceptions.from_http_response(response) google.api_core.exceptions.BadRequest: 400 PUT https://storage.googleapis.com/storage/v1/b/bucket_mikami?projection=full: Invalid argument
バケット削除
google.cloud.storage.Bucket クラスの delete メソッドで、バケットを削除します。
from google.cloud import storage from google.oauth2 import service_account import os import json key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) bucket_name = 'bucket_mikami' bucket = client.get_bucket(bucket_name) # delete bucket.delete() print("Bucket {} deleted.".format(bucket.name))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python bucket_delete.py Bucket bucket_mikami deleted.
オブジェクト関連操作
バッチなどの処理では、バケット関連の操作よりも、データの参照やオブジェクト作成など、オブジェクト関連の操作がメインになるかと思います。
クライアントライブラリから、オブジェクトの参照や作成、更新、削除を実行してみます。
オブジェクト情報参照
google.cloud.storage.Client クラスの list_blobs メソッドで、バケットにアップロード済みのオブジェクトの一覧を取得できます。
from google.cloud import storage from google.oauth2 import service_account import os import json from pprint import pprint key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) bucket_name = 'bucket_mikami' blobs = client.list_blobs(bucket_name) for blob in blobs: print('-------->') pprint(vars(blob))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object.py --------> {'_acl': <google.cloud.storage.acl.ObjectACL object at 0x7f6bdd0e8210>, '_bucket': <Bucket: bucket_mikami>, '_changes': set(), '_chunk_size': None, '_encryption_key': None, '_properties': {'bucket': 'bucket_mikami', 'contentType': 'application/vnd.ms-excel', 'crc32c': 'fl4Y3g==', 'etag': 'CKz62smBxOkCEAE=', 'generation': '1590031675735340', 'id': 'bucket_mikami/sample.csv/1590031675735340', 'kind': 'storage#object', 'md5Hash': 'tYiYF8Bmy8fF5+5bRkpt0Q==', 'mediaLink': 'https://storage.googleapis.com/download/storage/v1/b/bucket_mikami/o/sample.csv?generation=1590031675735340&alt=media', 'metageneration': '1', 'name': 'sample.csv', 'selfLink': 'https://www.googleapis.com/storage/v1/b/bucket_mikami/o/sample.csv', 'size': '1735', 'storageClass': 'STANDARD', 'timeCreated': '2020-05-21T03:27:55.735Z', 'timeStorageClassUpdated': '2020-05-21T03:27:55.735Z', 'updated': '2020-05-21T03:27:55.735Z'}, 'name': 'sample.csv'}
同じ操作は google.cloud.storage.Bucket クラス list_blobs でも可能です。
また、Bucket クラスには get_blob メソッドもあります。
(省略) bucket_name = 'bucket_mikami' # get list bucket = client.get_bucket(bucket_name) blobs = bucket.list_blobs() for obj in blobs: print('-------->') pprint(vars(obj)) # get blob = bucket.get_blob(obj.name) print('\t-------->') pprint(vars(blob))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_2.py --------> {'_acl': <google.cloud.storage.acl.ObjectACL object at 0x7f7c22c31e90>, '_bucket': <Bucket: bucket_mikami>, '_changes': set(), '_chunk_size': None, '_encryption_key': None, '_properties': {'bucket': 'bucket_mikami', 'contentType': 'application/vnd.ms-excel', 'crc32c': 'fl4Y3g==', 'etag': 'CKz62smBxOkCEAE=', 'generation': '1590031675735340', 'id': 'bucket_mikami/sample.csv/1590031675735340', 'kind': 'storage#object', 'md5Hash': 'tYiYF8Bmy8fF5+5bRkpt0Q==', 'mediaLink': 'https://storage.googleapis.com/download/storage/v1/b/bucket_mikami/o/sample.csv?generation=1590031675735340&alt=media', 'metageneration': '1', 'name': 'sample.csv', 'selfLink': 'https://www.googleapis.com/storage/v1/b/bucket_mikami/o/sample.csv', 'size': '1735', 'storageClass': 'STANDARD', 'timeCreated': '2020-05-21T03:27:55.735Z', 'timeStorageClassUpdated': '2020-05-21T03:27:55.735Z', 'updated': '2020-05-21T03:27:55.735Z'}, 'name': 'sample.csv'} --------> {'_acl': <google.cloud.storage.acl.ObjectACL object at 0x7f7c22c4a950>, '_bucket': <Bucket: bucket_mikami>, '_changes': set(), '_chunk_size': None, '_encryption_key': None, '_properties': {'bucket': 'bucket_mikami', 'contentType': 'application/vnd.ms-excel', 'crc32c': 'fl4Y3g==', 'etag': 'CKz62smBxOkCEAE=', 'generation': '1590031675735340', 'id': 'bucket_mikami/sample.csv/1590031675735340', 'kind': 'storage#object', 'md5Hash': 'tYiYF8Bmy8fF5+5bRkpt0Q==', 'mediaLink': 'https://storage.googleapis.com/download/storage/v1/b/bucket_mikami/o/sample.csv?generation=1590031675735340&alt=media', 'metageneration': '1', 'name': 'sample.csv', 'selfLink': 'https://www.googleapis.com/storage/v1/b/bucket_mikami/o/sample.csv', 'size': '1735', 'storageClass': 'STANDARD', 'timeCreated': '2020-05-21T03:27:55.735Z', 'timeStorageClassUpdated': '2020-05-21T03:27:55.735Z', 'updated': '2020-05-21T03:27:55.735Z'}, 'name': 'sample.csv'}
オブジェクト作成
google.cloud.storage.Bucket クラスの upload_from_string メソッドで、テキスト文字列を GCS オブジェクトとして出力してみます。
from google.cloud import storage from google.oauth2 import service_account import os import json key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) bucket_name = 'bucket_mikami' blob_name = 'test.csv' bucket = client.get_bucket(bucket_name) blob = bucket.blob(blob_name) stream = 'GCS オブジェクト作成のテスト' blob.upload_from_string(stream) print("Blob {} created.".format(blob_name))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_create.py Blob test.csv created.
管理コンソールからも、オブジェクトが作成されたことが確認できました。
ダウンロードしてファイルの中身も確認してみます。
GCS オブジェクト作成のテスト
ちゃんと Python コード内で指定した文字列がファイル出力されていることが確認できました。
また、upload_from_filename メソッドで、ローカルファイルをバケットにアップロードすることもできます。
Python コードと同じディレクトリに配置した、以下の都道府県コードのデータファイルをアップロードします。
code,name 01,北海道 02,青森県 03,岩手県 (省略) 47,沖縄県
(省略) bucket_name = 'bucket_mikami' file_name = 'pref_code_utf8.csv' bucket = client.get_bucket(bucket_name) blob = bucket.blob(file_name) blob.upload_from_filename(file_name) print("Blob {} created.".format(file_name))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_create_from_file.py Blob pref_code_utf8.csv created.
確認してみます。
(test_gcs) [ec2-user@ip-10-0-43-239 temp]$ gsutil cp gs://bucket_mikami/pref_code_utf8.csv ./ Copying gs://bucket_mikami/pref_code_utf8.csv... / [1 files][ 676.0 B/ 676.0 B] Operation completed over 1 objects/676.0 B. (test_gcs) [ec2-user@ip-10-0-43-239 temp]$ view pref_code_utf8.csv
code,name 01,北海道 02,青森県 03,岩手県 04,宮城県 05,秋田県 (省略) 45,宮崎県 46,鹿児島県 47,沖縄県
ちゃんとアップロードされたことが確認できました。
upload_from_file メソッドを使えば、データを格納したファイルオブジェクトからGCS オブジェクトを作成することもできます。
クライアントライブラリのコードを確認してみると、動作確認した upload_from_string も upload_from_filename も、内部的には upload_from_file を使用していました。
(省略) class Blob(_PropertyMixin): (省略) def upload_from_filename( self, filename, content_type=None, client=None, predefined_acl=None, if_generation_match=None, if_generation_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None, ): (省略) content_type = self._get_content_type(content_type, filename=filename) with open(filename, "rb") as file_obj: total_bytes = os.fstat(file_obj.fileno()).st_size self.upload_from_file( file_obj, content_type=content_type, client=client, size=total_bytes, predefined_acl=predefined_acl, if_generation_match=if_generation_match, if_generation_not_match=if_generation_not_match, if_metageneration_match=if_metageneration_match, if_metageneration_not_match=if_metageneration_not_match, ) def upload_from_string( self, data, content_type="text/plain", client=None, predefined_acl=None, if_generation_match=None, if_generation_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None, ): (省略) data = _to_bytes(data, encoding="utf-8") string_buffer = BytesIO(data) self.upload_from_file( file_obj=string_buffer, size=len(data), content_type=content_type, client=client, predefined_acl=predefined_acl, if_generation_match=if_generation_match, if_generation_not_match=if_generation_not_match, if_metageneration_match=if_metageneration_match, if_metageneration_not_match=if_metageneration_not_match, )
google.cloud.storage.Bucket クラスには、既存のオブジェクトを別のバケットにコピーする copy_blob メソッドもあります。
(省略) bucket_name = 'bucket_mikami' bucket = client.get_bucket(bucket_name) bucket_name_dst = 'test-mikami' dst_bucket = client.get_bucket(bucket_name_dst) blob_name = 'test.csv' blob = bucket.blob(blob_name) new_blob = bucket.copy_blob(blob, dst_bucket) new_blob.acl.save(blob.acl) print("Blob {} copied.".format(blob_name))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_copy.py Blob test.csv copied.
コピー元バケットのロケーションは US マルチリージョン、コピー先は東京リージョンでしたが、問題なくコピーできました。
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ gsutil ls -L -b gs://bucket_mikami/ | grep Location Location type: multi-region Location constraint: US (test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ gsutil ls -L -b gs://test-mikami/ | grep Location Location type: region Location constraint: ASIA-NORTHEAST1
オブジェクトデータ取得
google.cloud.storage.Blob クラスの download_as_string メソッドで、GCS オブジェクトデータを取得できます。
from google.cloud import storage from google.oauth2 import service_account import os import json key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) bucket_name = 'bucket_mikami' blob_name = 'test.csv' bucket = client.get_bucket(bucket_name) blob = bucket.blob(blob_name) stream = blob.download_as_string() print("read: [{}]".format(stream.decode('utf-8')))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_read.py read: [GCS オブジェクト作成のテスト]
なお、オブジェクトデータは bytes 型で返却されます。取得結果をそのまま print したところ以下の出力だったため、デコードを追加して print しました。。
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_read.py read: [b'GCS \xe3\x82\xaa\xe3\x83\x96\xe3\x82\xb8\xe3\x82\xa7\xe3\x82\xaf\xe3\x83\x88\xe4\xbd\x9c\xe6\x88\x90\xe3\x81\xae\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88']
オブジェクトをファイルとしてダウンロードする場合は、download_to_filename メソッドが便利です。
(省略) bucket_name = 'bucket_mikami' file_name = 'test.csv' bucket = client.get_bucket(bucket_name) blob = bucket.blob(file_name) blob.download_to_filename(file_name) print("File {} downloaded.".format(file_name))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_read_file.py File test.csv downloaded. (test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ ls -l | grep test.csv -rw-rw-r-- 1 ec2-user ec2-user 40 May 21 10:01 test.csv
オブジェクト作成同様、download_to_file で、ファイルオブジェクトとして取得することもできます。
また、google.cloud.storage.Client クラスにも、GCS オブジェクトをファイルオブジェクトとして取得する download_blob_to_file メソッドがあります。
(省略) bucket_name = 'bucket_mikami' file_name = 'test.csv' bucket = client.get_bucket(bucket_name) blob = bucket.blob(file_name) buffer = BytesIO() with BytesIO() as stream: client.download_blob_to_file(blob, stream) print("read: [{}]".format(stream.getvalue().decode('utf-8')))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_read_client.py read: [GCS オブジェクト作成のテスト]
download_blob_to_file のパラメータには、オブジェクトの uri を指定することもできます。
(省略) path = 'gs://bucket_mikami/test.csv' buffer = BytesIO() with BytesIO() as stream: client.download_blob_to_file(path, stream) print("read: [{}]".format(stream.getvalue().decode('utf-8')))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_read_client_2.py read: [GCS オブジェクト作成のテスト]
オブジェクトのパスが分かっている場合には、こちらの方がシンプルに取得できました。
オブジェクト削除
google.cloud.storage.Blob クラスの delete メソッドで、オブジェクトを削除できます。
from google.cloud import storage from google.oauth2 import service_account import os import json key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test-gcs.json') service_account_info = json.load(open(key_path)) credentials = service_account.Credentials.from_service_account_info(service_account_info) client = storage.Client( credentials=credentials, project=credentials.project_id, ) bucket_name = 'bucket_mikami' blob_name = 'test.csv' bucket = client.get_bucket(bucket_name) blob = bucket.blob(blob_name) print('blobs.exists -> {}'.format(blob.exists())) blob.delete() print("Blob {} deleted.".format(blob_name)) print('blobs.exists -> {}'.format(blob.exists()))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_delete.py blobs.exists -> True Blob test.csv deleted. blobs.exists -> False
オブジェクトの削除は google.cloud.storage.Bucket クラスの delete_blob メソッドでも可能です。
(省略) bucket_name = 'bucket_mikami' blob_name = 'test.csv' bucket = client.get_bucket(bucket_name) blob = bucket.blob(blob_name) print('blobs.exists -> {}'.format(blob.exists())) bucket.delete_blob(blob_name) print("Blob {} deleted.".format(blob_name)) print('blobs.exists -> {}'.format(blob.exists()))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_delete_2.py blobs.exists -> True Blob test.csv deleted. blobs.exists -> False
また、delete_blobs メソッドを使えば、複数のオブジェクトを一気に削除することもできます。
(省略) bucket_name = 'bucket_mikami' bucket = client.get_bucket(bucket_name) blobs = bucket.list_blobs() print('num: {}'.format(len(list(blobs)))) blobs = bucket.list_blobs() bucket.delete_blobs(blobs) print("Blob list deleted.") blobs = bucket.list_blobs() print('num: {}'.format(len(list(blobs))))
(test_gcs) [ec2-user@ip-10-0-43-239 test_gcs]$ python object_delete_list.py num: 2 Blob list deleted. num: 0
GCS 操作関連メソッド一覧
どのクラスのどのメソッドでどんな操作ができるのか、下表にまとめました。
function | class | method |
---|---|---|
バケット情報参照 | google.cloud.storage.Client | list_buckets |
get_bucket | ||
lookup_bucket | ||
バケット作成 | google.cloud.storage.Client | create_bucket |
google.cloud.storage.Bucket | create | |
バケット更新 | google.cloud.storage.Bucket | update |
バケット削除 | google.cloud.storage.Bucket | delete |
オブジェクト情報参照 | google.cloud.storage.Client | list_blobs |
google.cloud.storage.Bucket | list_blobs | |
get_blob | ||
オブジェクト作成 | google.cloud.storage.Bucket | copy_blob |
google.cloud.storage.Blob | upload_from_file | |
upload_from_filename | ||
upload_from_string | ||
オブジェクトデータ取得 | google.cloud.storage.Client | download_blob_to_file |
google.cloud.storage.Blob | download_to_file | |
download_to_filename | ||
download_as_string | ||
オブジェクト削除 | google.cloud.storage.Bucket | delete_blob |
delete_blobs | ||
google.cloud.storage.Blob | delete |
まとめ(所感)
GCS Python クライアントライブラリには、同じ操作ができるメソッドが複数あるので、処理に合わせて使い分けることができそうです。
どのクラスにどんなメソッドがあるか、パラメータに何を指定すればよいかなど、よく分からない場合はソースコードを直接参照すると良さそうです。